package main

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	// "reflect"
	"github.com/tinylib/msgp/msgp"

	"time"
)

// --------------------
// Encode
// 用gob进行数据编码
//
func Encode(data interface{}) ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(data)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// -------------------
// Decode
// 用gob进行数据解码
//
func Decode(data []byte, to interface{}) error {
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	return dec.Decode(to)
}

func test_gob() {
	sc := new(StudentRecordContainerTest)
	sc.Init("12345")
	b, er := Encode(sc)
	if er != nil {
		fmt.Println("encode fail: " + er.Error())
	}
	var out StudentRecordContainerTest
	if err := Decode(b, &out); err != nil {
		fmt.Println("decode fail: " + err.Error())
	}

}

func test_json() {
	sc := new(StudentRecordContainerTest)
	sc.Init("12345")
	j_sc, er := json.Marshal(sc)
	// fmt.Println(j_sc, reflect.TypeOf(j_sc), reflect.TypeOf(*sc))
	if er != nil {
		fmt.Println(er)
	}
	var sc_r StudentRecordContainerTest
	err := json.Unmarshal([]byte(j_sc), &sc_r)
	if err != nil {
		fmt.Println("Can't decode json message", err)
	}
}

func test_msg() {
	sc := new(StudentRecordContainerTest)
	sc.Init("12345")
	j_sc, er := sc.MarshalMsg(nil)
	if er != nil {
		fmt.Println("Can't encode message", er)
	}
	var sc_r StudentRecordContainerTest
	_, err := sc_r.UnmarshalMsg([]byte(j_sc))
	if err != nil {
		fmt.Println("Can't decode message", err)
	}
}

type Test struct {
	StrTest string
	MapTest map[string]int
}

//go:generate msgp

type StudentRecordContainerTest struct {
	StudentInfoList      string
	StudentLearnStatList *Test
	StudentComingTime    string
}

func (st *StudentRecordContainerTest) Init(StudentId string) {
	st.StudentComingTime = time.Now().Format("2006-01-02 15:04:05")
	st.StudentInfoList = StudentId
	// st.StudentLearnStatList = new(Test)
	st.StudentLearnStatList.StrTest = StudentId
	st.StudentLearnStatList.MapTest = make(map[string]int)
	st.StudentLearnStatList.MapTest[StudentId] = 0
	st.StudentLearnStatList.MapTest[st.StudentComingTime] = 1
}

func main() {

	// start_time := time.Now()
	// defer TimeoutWarning("test", "test", start_time, 0)
	// fmt.Println("json start time:", start_time)
	// for i := 0; i < 100000; i++ {
	// 	test_json()
	// }
	// end_time := time.Now()
	// cost := time.Since(start_time)
	// fmt.Println("json end time:", end_time, "cost:", cost)

	// test_all_serialize("gob")
	// test_all_serialize("json")
	// test_all_serialize("msg")
	test_msg()
	// test_gob()
}

func test_all_serialize(ser_type string) {
	start_time := time.Now()
	defer TimeoutWarning(ser_type, ser_type, start_time, 0)
	for i := 0; i < 1000000; i++ {
		if ser_type == "json" {
			test_json()
		} else if ser_type == "gob" {
			test_gob()
		} else if ser_type == "msg" {
			test_msg()
		}
	}
}

func TimeoutWarning(tag, detailed string, start time.Time, timeLimit float64) {
	dis := time.Now().Sub(start).Seconds()
	if dis > timeLimit {
		pubstr := fmt.Sprintf("%s using %f seconds", tag, dis)
		//stats.Publish(tag, pubstr)
		fmt.Println(pubstr)
	}
}

// NOTE: THIS FILE WAS PRODUCED BY THE
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
// DO NOT EDIT

// DecodeMsg implements msgp.Decodable
func (z *StudentRecordContainerTest) DecodeMsg(dc *msgp.Reader) (err error) {
	var field []byte
	_ = field
	var zxvk uint32
	zxvk, err = dc.ReadMapHeader()
	if err != nil {
		return
	}
	for zxvk > 0 {
		zxvk--
		field, err = dc.ReadMapKeyPtr()
		if err != nil {
			return
		}
		switch msgp.UnsafeString(field) {
		case "StudentInfoList":
			z.StudentInfoList, err = dc.ReadString()
			if err != nil {
				return
			}
		case "StudentLearnStatList":
			err = z.StudentLearnStatList.DecodeMsg(dc)
			if err != nil {
				return
			}
		case "StudentComingTime":
			z.StudentComingTime, err = dc.ReadString()
			if err != nil {
				return
			}
		default:
			err = dc.Skip()
			if err != nil {
				return
			}
		}
	}
	return
}

// EncodeMsg implements msgp.Encodable
func (z *StudentRecordContainerTest) EncodeMsg(en *msgp.Writer) (err error) {
	// map header, size 3
	// write "StudentInfoList"
	err = en.Append(0x83, 0xaf, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x4c, 0x69, 0x73, 0x74)
	if err != nil {
		return err
	}
	err = en.WriteString(z.StudentInfoList)
	if err != nil {
		return
	}
	// write "StudentLearnStatList"
	err = en.Append(0xb4, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x4c, 0x69, 0x73, 0x74)
	if err != nil {
		return err
	}
	err = z.StudentLearnStatList.EncodeMsg(en)
	if err != nil {
		return
	}
	// write "StudentComingTime"
	err = en.Append(0xb1, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65)
	if err != nil {
		return err
	}
	err = en.WriteString(z.StudentComingTime)
	if err != nil {
		return
	}
	return
}

// MarshalMsg implements msgp.Marshaler
func (z *StudentRecordContainerTest) MarshalMsg(b []byte) (o []byte, err error) {
	o = msgp.Require(b, z.Msgsize())
	// map header, size 3
	// string "StudentInfoList"
	o = append(o, 0x83, 0xaf, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x4c, 0x69, 0x73, 0x74)
	o = msgp.AppendString(o, z.StudentInfoList)
	// string "StudentLearnStatList"
	o = append(o, 0xb4, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x4c, 0x69, 0x73, 0x74)
	o, err = z.StudentLearnStatList.MarshalMsg(o)
	if err != nil {
		return
	}
	// string "StudentComingTime"
	o = append(o, 0xb1, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65)
	o = msgp.AppendString(o, z.StudentComingTime)
	return
}

// UnmarshalMsg implements msgp.Unmarshaler
func (z *StudentRecordContainerTest) UnmarshalMsg(bts []byte) (o []byte, err error) {
	var field []byte
	_ = field
	var zbzg uint32
	zbzg, bts, err = msgp.ReadMapHeaderBytes(bts)
	if err != nil {
		return
	}
	for zbzg > 0 {
		zbzg--
		field, bts, err = msgp.ReadMapKeyZC(bts)
		if err != nil {
			return
		}
		switch msgp.UnsafeString(field) {
		case "StudentInfoList":
			z.StudentInfoList, bts, err = msgp.ReadStringBytes(bts)
			if err != nil {
				return
			}
		case "StudentLearnStatList":
			bts, err = z.StudentLearnStatList.UnmarshalMsg(bts)
			if err != nil {
				return
			}
		case "StudentComingTime":
			z.StudentComingTime, bts, err = msgp.ReadStringBytes(bts)
			if err != nil {
				return
			}
		default:
			bts, err = msgp.Skip(bts)
			if err != nil {
				return
			}
		}
	}
	o = bts
	return
}

// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *StudentRecordContainerTest) Msgsize() (s int) {
	s = 1 + 16 + msgp.StringPrefixSize + len(z.StudentInfoList) + 21 + z.StudentLearnStatList.Msgsize() + 18 + msgp.StringPrefixSize + len(z.StudentComingTime)
	return
}

// DecodeMsg implements msgp.Decodable
func (z *Test) DecodeMsg(dc *msgp.Reader) (err error) {
	var field []byte
	_ = field
	var zajw uint32
	zajw, err = dc.ReadMapHeader()
	if err != nil {
		return
	}
	for zajw > 0 {
		zajw--
		field, err = dc.ReadMapKeyPtr()
		if err != nil {
			return
		}
		switch msgp.UnsafeString(field) {
		case "StrTest":
			z.StrTest, err = dc.ReadString()
			if err != nil {
				return
			}
		case "MapTest":
			var zwht uint32
			zwht, err = dc.ReadMapHeader()
			if err != nil {
				return
			}
			if z.MapTest == nil && zwht > 0 {
				z.MapTest = make(map[string]int, zwht)
			} else if len(z.MapTest) > 0 {
				for key, _ := range z.MapTest {
					delete(z.MapTest, key)
				}
			}
			for zwht > 0 {
				zwht--
				var zbai string
				var zcmr int
				zbai, err = dc.ReadString()
				if err != nil {
					return
				}
				zcmr, err = dc.ReadInt()
				if err != nil {
					return
				}
				z.MapTest[zbai] = zcmr
			}
		default:
			err = dc.Skip()
			if err != nil {
				return
			}
		}
	}
	return
}

// EncodeMsg implements msgp.Encodable
func (z *Test) EncodeMsg(en *msgp.Writer) (err error) {
	// map header, size 2
	// write "StrTest"
	err = en.Append(0x82, 0xa7, 0x53, 0x74, 0x72, 0x54, 0x65, 0x73, 0x74)
	if err != nil {
		return err
	}
	err = en.WriteString(z.StrTest)
	if err != nil {
		return
	}
	// write "MapTest"
	err = en.Append(0xa7, 0x4d, 0x61, 0x70, 0x54, 0x65, 0x73, 0x74)
	if err != nil {
		return err
	}
	err = en.WriteMapHeader(uint32(len(z.MapTest)))
	if err != nil {
		return
	}
	for zbai, zcmr := range z.MapTest {
		err = en.WriteString(zbai)
		if err != nil {
			return
		}
		err = en.WriteInt(zcmr)
		if err != nil {
			return
		}
	}
	return
}

// MarshalMsg implements msgp.Marshaler
func (z *Test) MarshalMsg(b []byte) (o []byte, err error) {
	o = msgp.Require(b, z.Msgsize())
	// map header, size 2
	// string "StrTest"
	o = append(o, 0x82, 0xa7, 0x53, 0x74, 0x72, 0x54, 0x65, 0x73, 0x74)
	o = msgp.AppendString(o, z.StrTest)
	// string "MapTest"
	o = append(o, 0xa7, 0x4d, 0x61, 0x70, 0x54, 0x65, 0x73, 0x74)
	o = msgp.AppendMapHeader(o, uint32(len(z.MapTest)))
	for zbai, zcmr := range z.MapTest {
		o = msgp.AppendString(o, zbai)
		o = msgp.AppendInt(o, zcmr)
	}
	return
}

// UnmarshalMsg implements msgp.Unmarshaler
func (z *Test) UnmarshalMsg(bts []byte) (o []byte, err error) {
	var field []byte
	_ = field
	var zhct uint32
	zhct, bts, err = msgp.ReadMapHeaderBytes(bts)
	if err != nil {
		return
	}
	for zhct > 0 {
		zhct--
		field, bts, err = msgp.ReadMapKeyZC(bts)
		if err != nil {
			return
		}
		switch msgp.UnsafeString(field) {
		case "StrTest":
			z.StrTest, bts, err = msgp.ReadStringBytes(bts)
			if err != nil {
				return
			}
		case "MapTest":
			var zcua uint32
			zcua, bts, err = msgp.ReadMapHeaderBytes(bts)
			if err != nil {
				return
			}
			if z.MapTest == nil && zcua > 0 {
				z.MapTest = make(map[string]int, zcua)
			} else if len(z.MapTest) > 0 {
				for key, _ := range z.MapTest {
					delete(z.MapTest, key)
				}
			}
			for zcua > 0 {
				var zbai string
				var zcmr int
				zcua--
				zbai, bts, err = msgp.ReadStringBytes(bts)
				if err != nil {
					return
				}
				zcmr, bts, err = msgp.ReadIntBytes(bts)
				if err != nil {
					return
				}
				z.MapTest[zbai] = zcmr
			}
		default:
			bts, err = msgp.Skip(bts)
			if err != nil {
				return
			}
		}
	}
	o = bts
	return
}

// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *Test) Msgsize() (s int) {
	s = 1 + 8 + msgp.StringPrefixSize + len(z.StrTest) + 8 + msgp.MapHeaderSize
	if z.MapTest != nil {
		for zbai, zcmr := range z.MapTest {
			_ = zcmr
			s += msgp.StringPrefixSize + len(zbai) + msgp.IntSize
		}
	}
	return
}
